package com.simple.ds.service.impl;

import cn.hutool.crypto.digest.DigestUtil;
import com.google.common.collect.Lists;
import com.google.common.primitives.Longs;
import com.google.gson.Gson;
import com.simple.common.entity.constant.Payment;
import com.simple.common.entity.po.ChannelMerchantEntity;
import com.simple.common.entity.po.RefundTradeEntity;
import com.simple.common.entity.po.TradeEntity;
import com.simple.common.entity.po.sys.Application;
import com.simple.common.entity.po.sys.Trade;
import com.simple.common.framework.scale.Scale;
import com.simple.ds.service.ChannelMerchantService;
import com.simple.ds.service.ProductService;
import com.simple.ds.service.TradeApi;
import com.simple.ds.service.TradeService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author yasud
 * @date 2021年09月19日 13:28
 * @description
 */
@Service
public class TradeApiImpl implements TradeApi {

    @Autowired
    TradeService tradeService;

    @Autowired
    ProductService productService;

    @Autowired
    ChannelMerchantService channelMerchantService;

    @Override
    public List<Trade> findByProperty_(Map<String, Object> param) {
        List<TradeEntity> tradeEntity = tradeService.findByParam(param);
        if (CollectionUtils.isNotEmpty(tradeEntity)) {
            List<Trade> collect = tradeEntity.stream().map(this::createTrade).collect(Collectors.toList());
            return collect;
        }
        return Lists.newArrayList();
    }

    @Override
    public Trade findByPropertyOne_(Map<String, Object> param) {
        TradeEntity tradeEntity = tradeService.findOneByParam(param);
        if (Objects.nonNull(tradeEntity)) {
            return createTrade(tradeEntity);
        }
        return null;
    }

    private Trade createTrade(TradeEntity entity) {
        if (Objects.isNull(entity)) return null;
        Trade trade = new Trade();
        trade.setId(entity.getId());
        trade.setMerchantName(entity.getMerchantName());
        trade.setMerchantNo(entity.getMerchantCode());
        trade.setMerchantOrderNo(entity.getMerchantOrderNo());
        trade.setChannelOrderNo(entity.getChannelOrderNo());
        trade.setAmount(entity.getOrderAmount() + "");
        trade.setCurrency(entity.getOrderCurrency());
        trade.setConvertOrderAmount(entity.getRealAmount() + "");
        trade.setConvertOrderCurrency(entity.getRealCurrency());
        trade.setPayAmount(entity.getRealAmount() + "");
        trade.setPayAmountCurrency(entity.getRealCurrency());
        trade.setMerchantNo(entity.getMerchantCode());
        trade.setApplicationId(Longs.fromByteArray(DigestUtil.sha256(entity.getMerchantCode() + "_application")));
        trade.setApplicationName(entity.getMerchantName());
        trade.setApplicationType(Application.Type.APP);
        trade.setAppId(entity.getMerchantCode());
        trade.setAppName(entity.getMerchantName());
        trade.setProductId(Longs.fromByteArray(DigestUtil.sha256(entity.getApiCode())));
        trade.setProductName(productService.code(entity.getApiCode()).name);
        trade.setChannelMerchantId(entity.getChannelMerchantId());
        trade.setChannelMerchantName(entity.getChannelMerchantName());
        trade.setChannelCode(entity.getChannelMerchantName());
        trade.setExpChannelId(entity.getChannelMerchantId());
        trade.setStatus(Trade.Status.valueOf(entity.getStatus().name()));
        trade.setType(Trade.Type.NORMAL_TRADE);
        trade.setMsg(entity.getMsg());
        trade.setChannelStatus(entity.getChannelStatus());
        trade.setChannelMsg(entity.getChannelMsg());
        if (Objects.nonNull(entity.getRefundStatus())) {
            trade.setRefundStatus(Trade.RefundStatus.valueOf(entity.getRefundStatus().name()));
        }
        trade.setRefundAmount(entity.getRefundAmount() + "");
        trade.setYmd(entity.getYmd());
        trade.setTime(entity.getTime());
        trade.setChannelId(entity.getChannelMerchantId());
        trade.setChannelName(entity.getChannelMerchantName());
        trade.setOrderDesc(entity.getOrderDesc());
        trade.setAsyncUrl(entity.getAsyncUrl());
        trade.setSyncUrl(entity.getRedirectUrl());
        trade.setExtraInfo(new Gson().toJson(entity.getExtraInfo()));
        trade.setBillingInfo(entity.getBillingInfo());
        trade.setGoodsList(entity.getShippingInfo());
        trade.setCardHolder(entity.getCardHolder());
        trade.setCardExYear(entity.getCardExpireYear());
        trade.setCardExMonth(entity.getCardExpireMonth());
        trade.setCardCvv(entity.getCardCvv());
        trade.setCardNo(entity.getCardNo());
        trade.setBillingInfo(entity.getBillingInfo());
        trade.setCardCvv(entity.getCardCvv());
        trade.setCreateTime(entity.getCreateTime());
        trade.setUpdateTime(entity.getUpdateTime());
        trade.setAccNumber(entity.getAccNumber());
        trade.setAccName(entity.getAccName());
        trade.setWithdrawalType(entity.getWithdrawalType());
        trade.setType(entity.getType());
        trade.setRemark1(entity.getRemark1());
        return trade;
    }


    @Override
    public Trade save_(Trade trade) {
        TradeEntity tradeEntity = new TradeEntity();
        tradeEntity.setMerchantCode(trade.getMerchantNo());
        tradeEntity.setMerchantName(trade.getMerchantName());
        Payment.PAY_TYPE code = productService.findCodeByHash(trade.getProductId());
        tradeEntity.setApiCode(code.code);
        tradeEntity.setApiName(code.name);
        ChannelMerchantEntity merchantEntity = channelMerchantService.getById(trade.getChannelMerchantId());
        tradeEntity.setChannelMerchantName(trade.getChannelMerchantName());
        tradeEntity.setChannelMerchantId(trade.getChannelMerchantId());
        tradeEntity.setChannelMerchantMid(merchantEntity.getMid());
        tradeEntity.setOrderAmount(Scale.scale(trade.getAmount()));
        tradeEntity.setOrderCurrency(trade.getCurrency());
        tradeEntity.setRealAmount(Scale.scale(trade.getPayAmount()));
        tradeEntity.setRealCurrency(trade.getPayAmountCurrency());
        tradeEntity.setStatus(TradeEntity.Status.valueOf(trade.getStatus().name()));
        tradeEntity.setRefundAmount(Scale.scale(trade.getRefundAmount()));
        if (Objects.nonNull(trade.getRefundStatus())) {
            tradeEntity.setRefundStatus(RefundTradeEntity.RefundStatus.valueOf(trade.getRefundStatus().name()));
        }
        tradeEntity.setMsg(trade.getMsg());
        tradeEntity.setMerchantOrderNo(trade.getMerchantOrderNo());
        tradeEntity.setChannelStatus(trade.getChannelStatus());
        tradeEntity.setChannelMsg(trade.getChannelMsg());
        tradeEntity.setCardNo(trade.getCardNo());
        tradeEntity.setCardExpireYear(trade.getCardExYear());
        tradeEntity.setCardExpireMonth(trade.getCardExMonth());
        tradeEntity.setCardCvv(trade.getCardCvv());
        tradeEntity.setCardHolder(trade.getCardHolder());
        tradeEntity.setRedirectUrl(trade.getSyncUrl());
        tradeEntity.setBillingInfo(trade.getBillingInfo());
        Map<String, Object> extraInfo = new Gson().fromJson(trade.getExtraInfo(), Map.class);
        tradeEntity.setExtraInfo(extraInfo);
        tradeEntity.setGoodsList(trade.getGoodsList());
        tradeEntity.setShippingInfo(trade.getShippingInfo());
        tradeEntity.setYmd(trade.getYmd());
        tradeEntity.setTime(trade.getTime());
        tradeEntity.setRemark1(trade.getRemark1());
        tradeEntity.setOrderDesc(trade.getOrderDesc());
        tradeEntity.setAccName(trade.getAccName());
        tradeEntity.setAccNumber(trade.getAccNumber());
        tradeEntity.setWithdrawalType(trade.getWithdrawalType());
        tradeEntity.setType(trade.getType());
        tradeService.save(tradeEntity);
        trade.setId(tradeEntity.getId());
        trade.setCreateTime(tradeEntity.getCreateTime());
        trade.setUpdateTime(tradeEntity.getUpdateTime());
        return trade;
    }

    @Override
    public Trade updateById_(Trade trade) {
        TradeEntity tradeEntity = new TradeEntity();
        tradeEntity.setId(trade.getId());
        tradeEntity.setMerchantCode(trade.getMerchantNo());
        tradeEntity.setMerchantName(trade.getMerchantName());
        if (Objects.nonNull(trade.getProductId())) {
            Payment.PAY_TYPE code = productService.findCodeByHash(trade.getProductId());
            tradeEntity.setApiCode(code.code);
            tradeEntity.setApiName(code.name);
        }
        ChannelMerchantEntity merchantEntity = channelMerchantService.getById(trade.getChannelMerchantId());
        tradeEntity.setChannelMerchantName(trade.getChannelMerchantName());
        tradeEntity.setChannelMerchantId(trade.getChannelMerchantId());
        tradeEntity.setChannelMerchantMid(merchantEntity.getMid());
        tradeEntity.setChannelOrderNo(trade.getChannelOrderNo());
        tradeEntity.setAsyncUrl(trade.getAsyncUrl());
        tradeEntity.setChannelStatus(trade.getChannelStatus());
        tradeEntity.setChannelMsg(trade.getChannelMsg());
        tradeEntity.setOrderAmount(Scale.scale(trade.getAmount()));
        tradeEntity.setOrderCurrency(trade.getCurrency());
        tradeEntity.setRealAmount(Scale.scale(trade.getPayAmount()));
        tradeEntity.setRealCurrency(trade.getPayAmountCurrency());
        tradeEntity.setStatus(TradeEntity.Status.valueOf(trade.getStatus().name()));
        tradeEntity.setChannelAmount(Scale.scale(trade.getPayAmount()));
        tradeEntity.setChannelCurrency(trade.getPayAmountCurrency());
        tradeEntity.setRefundAmount(Scale.scale(trade.getRefundAmount()));
        if (Objects.nonNull(trade.getRefundStatus())) {
            tradeEntity.setRefundStatus(RefundTradeEntity.RefundStatus.valueOf(trade.getRefundStatus().name()));
        }
        tradeEntity.setMsg(trade.getMsg());
        tradeEntity.setMerchantOrderNo(trade.getMerchantOrderNo());
        tradeEntity.setChannelStatus(trade.getChannelStatus());
        tradeEntity.setChannelMsg(trade.getChannelMsg());
        tradeEntity.setCardNo(trade.getCardNo());
        tradeEntity.setCardExpireYear(trade.getCardExYear());
        tradeEntity.setCardExpireMonth(trade.getCardExMonth());
        tradeEntity.setCardCvv(trade.getCardCvv());
        tradeEntity.setCardHolder(trade.getCardHolder());
        tradeEntity.setRedirectUrl(trade.getSyncUrl());
        tradeEntity.setBillingInfo(trade.getBillingInfo());
        if (StringUtils.isNotBlank(trade.getExtraInfo())) {
            Map<String, Object> extraInfo = new Gson().fromJson(trade.getExtraInfo(), Map.class);
            tradeEntity.setExtraInfo(extraInfo);
        }
        tradeEntity.setAccName(trade.getAccName());
        tradeEntity.setAccNumber(trade.getAccNumber());
        tradeEntity.setWithdrawalType(trade.getWithdrawalType());
        tradeEntity.setType(trade.getType());
        tradeEntity.setGoodsList(trade.getGoodsList());
        tradeEntity.setShippingInfo(trade.getShippingInfo());
        tradeEntity.setYmd(trade.getYmd());
        tradeEntity.setTime(trade.getTime());
        tradeEntity.setOrderDesc(trade.getOrderDesc());
        tradeEntity.setRemark1(trade.getRemark1());
        tradeEntity.setId(trade.getId());
        tradeService.updateById(tradeEntity);
        return trade;
    }

    @Override
    public int findByRiskDoNotHour(String cardNo, String cardHolder, String channelStatus, Date date, Long channelId) {
        return tradeService.findByRiskDoNotHour(cardNo, cardHolder, channelStatus, date, channelId);
    }

    @Override
    public int findByRiskConfigError(String cardNo, String channelStatus, Date date, Long channelId) {
        return tradeService.findByRiskConfigError(cardNo, channelStatus, date, channelId);
    }

    @Override
    public int findByRiskInvalidTransaction(String cardHolder, String channelStatus, Date date, Long channelId) {
        return tradeService.findByRiskInvalidTransaction(cardHolder, channelStatus, date, channelId);
    }

    @Override
    public int findByRiskRestrictedCard(String channelStatus, String cardNo, String cardHolder, Date date, Long channelId) {
        return tradeService.findByRiskRestrictedCard(channelStatus, cardNo, cardHolder, date, channelId);
    }

    @Override
    public int findByRiskCardHolderCount(String ipAddress, String cardNo, String cardHolder, String date, Long channelId) {
        return tradeService.findByRiskCardHolderCount(ipAddress, cardNo, cardHolder, date, channelId);
    }

    @Override
    public List<Trade> findTradeByChannelOrderNo(String channelTradeNo) {
        List<TradeEntity> tradeEntities = tradeService.findTradeByChannelOrderNo(channelTradeNo);
        if (CollectionUtils.isNotEmpty(tradeEntities)) {
            return tradeEntities.stream().map(this::createTrade).collect(Collectors.toList());
        }
        return Lists.newArrayList();
    }

    @Override
    public Trade findById_(Long tradeNo) {
        TradeEntity tradeEntity = tradeService.getById(tradeNo);
        return createTrade(tradeEntity);
    }
}
